﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection.Emit;

namespace SscLib
{
    /// <summary>
    /// Absract base class for methods and constructors.
    /// Provides general functionality common to method body definitions, 
    /// such as access to ILGenerator, argument list,
    /// adding arguments, variables and local blocks (scopes).
    /// </summary>
    public abstract class MethodSymbolBase : ScopeSymbol
    {
        /// <summary>Dictionary containing symbols local to the method.</summary>
        protected Dictionary<string, Symbol> members = new Dictionary<string, Symbol>(StringComparer.CurrentCultureIgnoreCase);

        /// <summary>List of arguments for this method.</summary>
        protected List<ArgumentSymbol> args = new List<ArgumentSymbol>();

        /// <summary>ILGenerator for this method symbol.</summary>
        protected ILGenerator ilGenerator;

        /// <summary>
        /// MethodSymbolBase constructor.
        /// </summary>
        /// <param name="name">Method name.</param>
        /// <param name="type">Method returning type.</param>
        public MethodSymbolBase(string name, TypeSymbol type) : base(name, type)
        {
        }

        /// <summary>
        /// Returns an IList of this methods arguments.
        /// </summary>
        public IList<ArgumentSymbol> Args
        {
            get
            {
                return args;
            }
        }

        /// <summary>
        /// Returns the argument symbol at at the specified position.
        /// </summary>
        /// <param name="pos">Indexed position of the requested argument symbol.</param>
        /// <returns>Returns the argument symbol at the specified position.</returns>
        public ArgumentSymbol GetArgument(int pos)
        {
            return args[pos];
        }

        public override ArgumentSymbol AddArgument(string name, TypeSymbol type)
        {
            ArgumentSymbol arg = base.AddArgument(name, type);

            //Arguments to instance methods start with adress 1, since the THIS pointer is argument 0
            //So we add the argument to the argument collection before we assign adress.
            //args.Add(name, arg);
            args.Add(arg);
            arg.Adr = args.Count;
            return arg;
        }

        public virtual ILGenerator ILGenerator
        {
            get { return this.ilGenerator; }
            set { this.ilGenerator = value; }
        }

        //public override VariableSymbol AddVariable(string name, TypeSymbol type)
        //{

        //    VariableSymbol var = base.AddVariable(name, type);

        //    //Arguments to instance methods start with adress 1, since the THIS pointer is argument 0
        //    //So we add the argument to the argument collection before we assign adress.
        //    args.Add(name, var);
        //    var.Adr = args.Count;
        //    return var;
        //}

        public override string ToString()
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("Method(");
            sb.Append(this.Scope.Name + "::");
            sb.Append(Name);
            //sb.Append(":");
            //sb.Append(ReturnType.TypeName);
            sb.AppendLine(")");
            sb.Append(base.ToString());

            return sb.ToString();
        }

        /// <summary>Returns a Dictionary containing Symbols defined inside this Scope.</summary>
        public override Dictionary<string, Symbol> Members
        {
            get { return this.members; }
        }
    }
}
